package com.enjoy.adv;

import com.enjoy.adv.client.ClientInit;
import com.enjoy.adv.vo.MessageType;
import com.enjoy.adv.vo.MyHeader;
import com.enjoy.adv.vo.MyMessage;
import com.enjoy.adv.vo.NettyConstant;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * Created by HP on 2019/7/19.
 */
public class NettyClient implements Runnable {
    private static final Log LOG = LogFactory.getLog(NettyClient.class);
    private Channel channel;
    private EventLoopGroup group = new NioEventLoopGroup();
    private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

    /*是否用户主动关闭连接的标志值*/
    private volatile boolean userClose = false;
    /*连接是否成功关闭的标志值*/
    private volatile boolean connected = false;


    public boolean isConnected() {
        return connected;
    }

    public void connect(final int port, String host) throws InterruptedException {
        try {
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ClientInit());
            ChannelFuture future = b.connect(new InetSocketAddress(host, port)).sync();
            channel = future.sync().channel();
            /*连接成功后通知等待线程，连接已经建立*/
            synchronized (this) {
                this.connected = true;
                this.notifyAll();
            }
            future.channel().closeFuture().sync();
        } finally {
            if (!userClose) {/*非用户主动关闭，说明发生了网络问题，需要进行重连操作*/
                System.out.println("异常，可能生服务器异常或网络问题，准备重连");
                //再次发起重连操作
                executorService.execute(new Runnable() {
                    public void run() {
                        try {
                            TimeUnit.SECONDS.sleep(1);
                            connect(NettyConstant.REMOTE_PORT, NettyConstant.REMOTE_IP);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            } else {/*用户主动关闭，释放资源*/
                channel = null;
                group.shutdownGracefully().sync();

                synchronized (this) {
                    this.connected = false;
                    this.notifyAll();
                }
            }
        }

    }

    public void run() {
        try {
            connect(NettyConstant.REMOTE_PORT,NettyConstant.REMOTE_IP);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /*------------以下方法供业务方使用--------------------------*/
    public void send(String message) {
        if(channel==null||!channel.isActive()){
            throw new IllegalStateException("和服务器还未未建立起有效连接！" +
                    "请稍后再试！！");
        }
        MyMessage msg = new MyMessage();
        MyHeader myHeader = new MyHeader();
        myHeader.setType(MessageType.SERVICE_REQ.getValue());
        msg.setMyHeader(myHeader);
        msg.setBody(message);
        channel.writeAndFlush(msg);
    }

    public void close() {
        userClose = true;
        channel.close();
    }


}
